{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# GeneticFeatureSelectorNode\n",
    "\n",
    "Whereas the `FSSNode` selects from a predefined list of subsets of features, the `GeneticFeatureSelectorNode` uses evolutionary algorithms to optimize a novel subset of features from scratch. This is useful where there is no predefined grouping of features. \n",
    "\n",
    "To initalize the `GeneticFeatureSelectorNode` you simply need to pass in the total number of features (i.e number of columns) in your dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For these examples, we create a dummy dataset where the first six columns are informative and the rest are uninformative."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/anaconda3/envs/tpotenv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>a</th>\n",
       "      <th>b</th>\n",
       "      <th>c</th>\n",
       "      <th>d</th>\n",
       "      <th>e</th>\n",
       "      <th>f</th>\n",
       "      <th>g</th>\n",
       "      <th>h</th>\n",
       "      <th>i</th>\n",
       "      <th>j</th>\n",
       "      <th>k</th>\n",
       "      <th>l</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.431031</td>\n",
       "      <td>1.889841</td>\n",
       "      <td>0.403235</td>\n",
       "      <td>0.130347</td>\n",
       "      <td>1.245051</td>\n",
       "      <td>-3.356587</td>\n",
       "      <td>0.254612</td>\n",
       "      <td>0.477369</td>\n",
       "      <td>0.145158</td>\n",
       "      <td>0.633607</td>\n",
       "      <td>0.200373</td>\n",
       "      <td>0.037735</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.016308</td>\n",
       "      <td>-1.035908</td>\n",
       "      <td>-1.625176</td>\n",
       "      <td>1.803391</td>\n",
       "      <td>0.442258</td>\n",
       "      <td>-0.844052</td>\n",
       "      <td>0.141507</td>\n",
       "      <td>0.024659</td>\n",
       "      <td>0.769976</td>\n",
       "      <td>0.658990</td>\n",
       "      <td>0.971987</td>\n",
       "      <td>0.570931</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3.769469</td>\n",
       "      <td>0.209185</td>\n",
       "      <td>-1.303033</td>\n",
       "      <td>4.077509</td>\n",
       "      <td>2.935603</td>\n",
       "      <td>1.243487</td>\n",
       "      <td>0.088988</td>\n",
       "      <td>0.377935</td>\n",
       "      <td>0.019007</td>\n",
       "      <td>0.923725</td>\n",
       "      <td>0.760895</td>\n",
       "      <td>0.316752</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-2.583292</td>\n",
       "      <td>0.172831</td>\n",
       "      <td>-1.531697</td>\n",
       "      <td>-0.078774</td>\n",
       "      <td>1.656190</td>\n",
       "      <td>0.475652</td>\n",
       "      <td>0.741539</td>\n",
       "      <td>0.179612</td>\n",
       "      <td>0.993759</td>\n",
       "      <td>0.624101</td>\n",
       "      <td>0.290679</td>\n",
       "      <td>0.946652</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-0.833504</td>\n",
       "      <td>3.209340</td>\n",
       "      <td>-0.928798</td>\n",
       "      <td>0.345765</td>\n",
       "      <td>1.599057</td>\n",
       "      <td>0.242801</td>\n",
       "      <td>0.359656</td>\n",
       "      <td>0.697036</td>\n",
       "      <td>0.643063</td>\n",
       "      <td>0.198362</td>\n",
       "      <td>0.725530</td>\n",
       "      <td>0.974992</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          a         b         c         d         e         f         g  \\\n",
       "0  0.431031  1.889841  0.403235  0.130347  1.245051 -3.356587  0.254612   \n",
       "1  0.016308 -1.035908 -1.625176  1.803391  0.442258 -0.844052  0.141507   \n",
       "2  3.769469  0.209185 -1.303033  4.077509  2.935603  1.243487  0.088988   \n",
       "3 -2.583292  0.172831 -1.531697 -0.078774  1.656190  0.475652  0.741539   \n",
       "4 -0.833504  3.209340 -0.928798  0.345765  1.599057  0.242801  0.359656   \n",
       "\n",
       "          h         i         j         k         l  \n",
       "0  0.477369  0.145158  0.633607  0.200373  0.037735  \n",
       "1  0.024659  0.769976  0.658990  0.971987  0.570931  \n",
       "2  0.377935  0.019007  0.923725  0.760895  0.316752  \n",
       "3  0.179612  0.993759  0.624101  0.290679  0.946652  \n",
       "4  0.697036  0.643063  0.198362  0.725530  0.974992  "
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import tpot\n",
    "from tpot.search_spaces.nodes import *\n",
    "from tpot.search_spaces.pipelines import *\n",
    "import tpot\n",
    "import sklearn.datasets\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import tpot\n",
    "import sklearn.datasets\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import numpy as np\n",
    "from tpot.search_spaces.nodes import *\n",
    "from tpot.search_spaces.pipelines import *\n",
    "from tpot.config import get_search_space\n",
    "\n",
    "\n",
    "X, y = sklearn.datasets.make_classification(n_samples=1000, n_features=6, n_informative=6, n_redundant=0, n_repeated=0, n_classes=2, n_clusters_per_class=2, weights=None, flip_y=0.01, class_sep=1.0, hypercube=True, shift=0.0, scale=1.0, shuffle=True, random_state=None)\n",
    "X = np.hstack([X, np.random.rand(X.shape[0],6)]) #add six uninformative features\n",
    "X = pd.DataFrame(X, columns=['a','b','c','d','e','f','g','h','i', 'j', 'k', 'l']) # a, b ,c the rest are uninformative\n",
    "X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(X, y, train_size=0.75, test_size=0.25)\n",
    "\n",
    "X.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "gfs_sp = GeneticFeatureSelectorNode(n_features=X.shape[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each GeneticFeatureSelectorNode will select a new subset of features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>b</th>\n",
       "      <th>j</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>89</th>\n",
       "      <td>0.067735</td>\n",
       "      <td>0.839366</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>897</th>\n",
       "      <td>-0.175982</td>\n",
       "      <td>0.050951</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>824</th>\n",
       "      <td>-0.503185</td>\n",
       "      <td>0.826335</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>305</th>\n",
       "      <td>2.775297</td>\n",
       "      <td>0.877498</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>774</th>\n",
       "      <td>3.143969</td>\n",
       "      <td>0.429360</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>310</th>\n",
       "      <td>1.402502</td>\n",
       "      <td>0.506769</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>333</th>\n",
       "      <td>2.384090</td>\n",
       "      <td>0.047125</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>259</th>\n",
       "      <td>5.262763</td>\n",
       "      <td>0.500726</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>1.107717</td>\n",
       "      <td>0.768569</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>757</th>\n",
       "      <td>3.606505</td>\n",
       "      <td>0.557151</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>750 rows × 2 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            b         j\n",
       "89   0.067735  0.839366\n",
       "897 -0.175982  0.050951\n",
       "824 -0.503185  0.826335\n",
       "305  2.775297  0.877498\n",
       "774  3.143969  0.429360\n",
       "..        ...       ...\n",
       "310  1.402502  0.506769\n",
       "333  2.384090  0.047125\n",
       "259  5.262763  0.500726\n",
       "30   1.107717  0.768569\n",
       "757  3.606505  0.557151\n",
       "\n",
       "[750 rows x 2 columns]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "selector = gfs_sp.generate().export_pipeline()\n",
    "selector.set_output(transform=\"pandas\") #by default sklearn selectors return numpy arrays. this will make it return pandas dataframes\n",
    "selector.fit(X_train, y_train)\n",
    "selector.transform(X_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>k</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>89</th>\n",
       "      <td>0.179639</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>897</th>\n",
       "      <td>0.430166</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>824</th>\n",
       "      <td>0.354605</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>305</th>\n",
       "      <td>0.949369</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>774</th>\n",
       "      <td>0.499857</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>310</th>\n",
       "      <td>0.624468</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>333</th>\n",
       "      <td>0.995309</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>259</th>\n",
       "      <td>0.138835</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>0.548930</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>757</th>\n",
       "      <td>0.643055</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>750 rows × 1 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            k\n",
       "89   0.179639\n",
       "897  0.430166\n",
       "824  0.354605\n",
       "305  0.949369\n",
       "774  0.499857\n",
       "..        ...\n",
       "310  0.624468\n",
       "333  0.995309\n",
       "259  0.138835\n",
       "30   0.548930\n",
       "757  0.643055\n",
       "\n",
       "[750 rows x 1 columns]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "selector = gfs_sp.generate().export_pipeline()\n",
    "selector.set_output(transform=\"pandas\") #by default sklearn selectors return numpy arrays. this will make it return pandas dataframes\n",
    "selector.fit(X_train, y_train)\n",
    "selector.transform(X_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mutation and crossover can add or remove subsets from the learned feature set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "selected features:  Index(['a', 'j'], dtype='object')\n"
     ]
    }
   ],
   "source": [
    "selector_ind = gfs_sp.generate()\n",
    "selector = selector_ind.export_pipeline()\n",
    "selected_features = X.columns[selector.mask]\n",
    "\n",
    "print(\"selected features: \", selected_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "selected features:  Index(['a', 'h', 'j'], dtype='object')\n"
     ]
    }
   ],
   "source": [
    "selector_ind.mutate()\n",
    "selector = selector_ind.export_pipeline()\n",
    "selected_features = X.columns[selector.mask]\n",
    "print(\"selected features: \", selected_features)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/ketrong/Desktop/tpotvalidation/tpot/tpot/tpot_estimator/estimator.py:456: UserWarning: Both generations and max_time_mins are set. TPOT will terminate when the first condition is met.\n",
      "  warnings.warn(\"Both generations and max_time_mins are set. TPOT will terminate when the first condition is met.\")\n",
      "Generation: 100%|██████████| 10/10 [00:53<00:00,  5.33s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9458645653148825\n"
     ]
    }
   ],
   "source": [
    "import tpot\n",
    "import sklearn.datasets\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import numpy as np\n",
    "from tpot.search_spaces.nodes import *\n",
    "from tpot.search_spaces.pipelines import *\n",
    "\n",
    "gfs_sp = GeneticFeatureSelectorNode(n_features=X.shape[1])\n",
    "classifiers_sp = get_search_space('RandomForestClassifier')\n",
    "final_classification_search_space = SequentialPipeline([gfs_sp, classifiers_sp])\n",
    "\n",
    "est = tpot.TPOTEstimator(  population_size=32,\n",
    "                            generations=10, \n",
    "                            scorers=[\"roc_auc_ovr\", tpot.objectives.complexity_scorer],\n",
    "                            scorers_weights=[1.0, -1.0],\n",
    "                            n_jobs=32,\n",
    "                            classification=True,\n",
    "                            search_space = final_classification_search_space,\n",
    "                            verbose=1,\n",
    "                            )\n",
    "\n",
    "\n",
    "scorer = sklearn.metrics.get_scorer('roc_auc_ovo')\n",
    "\n",
    "est.fit(X_train, y_train)\n",
    "print(scorer(est, X_test, y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                 MaskSelector(mask=array([ True,  True,  True,  True,  True,  True, False, False,  True,\n",
       "       False,  True,  True]))),\n",
       "                (&#x27;randomforestclassifier&#x27;,\n",
       "                 RandomForestClassifier(class_weight=&#x27;balanced&#x27;,\n",
       "                                        criterion=&#x27;entropy&#x27;,\n",
       "                                        max_features=0.487196536075,\n",
       "                                        min_samples_leaf=5, min_samples_split=3,\n",
       "                                        n_estimators=128, n_jobs=1))])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" ><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;Pipeline<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                 MaskSelector(mask=array([ True,  True,  True,  True,  True,  True, False, False,  True,\n",
       "       False,  True,  True]))),\n",
       "                (&#x27;randomforestclassifier&#x27;,\n",
       "                 RandomForestClassifier(class_weight=&#x27;balanced&#x27;,\n",
       "                                        criterion=&#x27;entropy&#x27;,\n",
       "                                        max_features=0.487196536075,\n",
       "                                        min_samples_leaf=5, min_samples_split=3,\n",
       "                                        n_estimators=128, n_jobs=1))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" ><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">MaskSelector</label><div class=\"sk-toggleable__content fitted\"><pre>MaskSelector(mask=array([ True,  True,  True,  True,  True,  True, False, False,  True,\n",
       "       False,  True,  True]))</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-3\" type=\"checkbox\" ><label for=\"sk-estimator-id-3\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;RandomForestClassifier<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.ensemble.RandomForestClassifier.html\">?<span>Documentation for RandomForestClassifier</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>RandomForestClassifier(class_weight=&#x27;balanced&#x27;, criterion=&#x27;entropy&#x27;,\n",
       "                       max_features=0.487196536075, min_samples_leaf=5,\n",
       "                       min_samples_split=3, n_estimators=128, n_jobs=1)</pre></div> </div></div></div></div></div></div>"
      ],
      "text/plain": [
       "Pipeline(steps=[('maskselector',\n",
       "                 MaskSelector(mask=array([ True,  True,  True,  True,  True,  True, False, False,  True,\n",
       "       False,  True,  True]))),\n",
       "                ('randomforestclassifier',\n",
       "                 RandomForestClassifier(class_weight='balanced',\n",
       "                                        criterion='entropy',\n",
       "                                        max_features=0.487196536075,\n",
       "                                        min_samples_leaf=5, min_samples_split=3,\n",
       "                                        n_estimators=128, n_jobs=1))])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "est.fitted_pipeline_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "selected features:  Index(['a', 'b', 'c', 'd', 'e', 'f', 'i', 'k', 'l'], dtype='object')\n"
     ]
    }
   ],
   "source": [
    "selected_features = X.columns[est.fitted_pipeline_.steps[0][1].mask]\n",
    "print(\"selected features: \", selected_features)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Custom objective function to minimize number of selected features\n",
    "We can create a custom objective function that returns the number of features selected per pipeline. The `other_objective_functions` parameter is for objective functions that do not require fitted pipelines and do not require cross validation. Since we know that the selector instance gets its features from its parameters, not through fitting, we can create an objective for the `other_objective_functions` parameter. \n",
    "We set the weights to -1 because we would like to minimize the number of features selected. We also give it a name so that we can more easily access it in the `evaluated_individuals` dataframe."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/ketrong/Desktop/tpotvalidation/tpot/tpot/tpot_estimator/estimator.py:456: UserWarning: Both generations and max_time_mins are set. TPOT will terminate when the first condition is met.\n",
      "  warnings.warn(\"Both generations and max_time_mins are set. TPOT will terminate when the first condition is met.\")\n",
      "Generation: 100%|██████████| 10/10 [00:47<00:00,  4.73s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9414440386956244\n"
     ]
    }
   ],
   "source": [
    "def number_of_selected_features(est):\n",
    "   return sum(est.steps[0][1].mask)\n",
    "\n",
    "gfs_sp = GeneticFeatureSelectorNode(n_features=X.shape[1])\n",
    "classifiers_sp = get_search_space('RandomForestClassifier')\n",
    "final_classification_search_space = SequentialPipeline([gfs_sp, classifiers_sp])\n",
    "\n",
    "est = tpot.TPOTEstimator(  \n",
    "                           population_size=32,\n",
    "                           generations=10, \n",
    "                           scorers=[\"roc_auc_ovr\", tpot.objectives.complexity_scorer],\n",
    "                           scorers_weights=[1.0, -1.0],\n",
    "                           other_objective_functions=[number_of_selected_features],\n",
    "                           other_objective_functions_weights = [-1],\n",
    "                           objective_function_names = [\"Number of selected features\"],\n",
    "\n",
    "                           n_jobs=32,\n",
    "                           classification=True,\n",
    "                           search_space = final_classification_search_space,\n",
    "                           verbose=2,\n",
    "                            )\n",
    "\n",
    "scorer = sklearn.metrics.get_scorer('roc_auc_ovo')\n",
    "\n",
    "est.fit(X_train, y_train)\n",
    "print(scorer(est, X_test, y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "selected features:  Index(['b', 'c', 'd', 'e', 'f', 'g'], dtype='object')\n"
     ]
    }
   ],
   "source": [
    "selected_features = X.columns[est.fitted_pipeline_.steps[0][1].mask]\n",
    "print(\"selected features: \", selected_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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40RERaNF97hzdl2jRo3kwAHXWdFw8uRJGTFihPTr10+NGz344INFOmdcXJwaX8DzOp+nMGPtvoDpXa85BWzA8WvfHFD1OuHa40Sle7rr6NGjfX0ZZYJen+wikpSUpMap88uuQ1d2r169pEmTJvLpp5/KmjVrVOb3I4884vE5Me506aWXqueywXg5jl11b2uzlreLJDRAYES9aWuPE5HesA4FejXPnz/v60sps3zePY5gixYzusSPHTsmTzzxhGr1Dh48OM9jEUjRnY7HIlAj6xwJXatWrVLJaNWrV3fZ6saNgH3LHXMnkQleoUIF1dUOyDwfMmSItGvXTk0pw5QvjE3bssl1E5/qPsjFp+q1ljfXHieii00QZiKfhi3tP/74QwVoJKLddNNNaq71Dz/8IBUrVszzWGR0T5kyRRYvXuzwy8QcbIwnDxo0yOU5tmzZIm3atFFftgCN/584cWLuY26++WZ54YUXVBnmYyOof/nlly7nfeugoK03w4OLvvJOceLa40QXD8NGB08lqeWJD55OKpFhpPT0dLn//vvVtKTQ0FDp2rWrbN68WX777Tfp0aOHegz2WECL+4477nBoVGEGDxpDGFbEwln20Dq/66671Gd7VFSUamghcdcGj8dn7zvvvCN169ZV5yYNW9qYb30xrrzySpfltoCc33gLJrcXZNSoUerLFO7maYvv8/Jcrj1uv4SpDdceJ9IncROBFw2j+fPnq17N5557Ti00ham5KL/xxhvV2hgIvLa5x4DHo0H0448/qlk9COhdunTJ/cxGowqPX7FihZo18+abb6qhzn379qlAD+gRxTkw9FkcS36WRj5vaZOH/CyZ2LeZdHWap43jJ/o1wxo8ouPa486bhnDtcSJ9EjcxJIjps1jOGUORGH58++23VbDFQlO24IpWOFrT9lNWMfsHw5tY/ArraGCo0ZYntH79etm0aZOaBotyPAY9m0g8/uSTTxy6xLHpEhpheD7SsKVNngkLDJQnl/4qrWvFqMVU7DcMmbZitwrouuHa40TFl7jpjb8bJAFj4Q+0kG2wZDTyfHbv3u12QSjnIItkYtuynegGR24Rhj/tpaamqnPaoGXvamiU/sGgbajUrGxZu+e0+nJlzDUXVmTSDdceJyqdiZvO+0FgzNu2WQoCNoK4q10Q0dq2iYiIKIErNRuDtqGS09zv4qXjLl9E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",
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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/6eOeQUSDQfV69ffj95DDRXN7uvUFxSBXwiIv8dO9MWIeqsUiPSlgH7PzrGZ3c8sO587gHzCBwARbu7cuT79c/bRRx/59u7d69u+fbvvtdde85UvX94XExPj+/XXX32//PKLr0iRIr7x48cHPfa7777zFS1aNGj5RRdd5PY3c+bMdM/Vp08fX8mSJYOWffPNN277W2+9NWj5fffd55Z//PHHqctq1qzpli1evDho208++cQtP++883zJycmpy3v27OkrVKiQr0uXLkHbt23b1u0r0OHDh9O1t3Pnzr6zzz47aJm/DcuWLUtdtmfPHl/x4sV9Q4cOTV02atQot93ChQvT7ffkyZPu57x583yFCxf2ffbZZ0Hr9d7psStWrPCdil5nxYoV3Ws+cuRI6vK3337bPVbPn/Yz/vLLL31Zufrqq31RUVG+n3/+OXXZzp07faVLl/Z16NAh3T47duyY+nrk3nvvdcfK/v37g44J3fzef/9999j33nsv6LmbNGkStF1GdIzqsaNHj87w+NK6cePGBS1v3ry5r0WLFqn39X5ru/nz5wdtp+Mqo+Vp6bm13YYNG1x7tmzZ4ps1a5Y7BipVquQ7dOiQ7/jx475jx44FPe6PP/5w6/v165e6TI/VvmJjY91xFOiyyy7zNW7c2Hf06NHUZXqv27Vr56tXr17qsn/9619uH/o7CKT96bPs1KmT78SJE6nLn3nmGbf9nDlzMn2d/s84o1vg353+RgL/fnJybGb3M8vscweQfzAsEEC+oW+29Q2xhqWpx0k9DOo10rfmmkeiXhb1WukbbP+tcuXKVq9evXRDnfTNu761zg4VzRANLQukHix55513gpar50XfcmdEQ+4Cv4nXN+HqCVHPUSAt13BGDUf0C5y35f+m/qKLLrLNmze7+4E0ZFC9O35639Q7pG391LPQtGlT9017Wv5iBxo2pR6GBg0aBL2v/uFlad/XQF999ZWbS6XeNQ0X87v88svd/tK+b9mhHgQVZlDPiIY6+lWpUsVuuOEG18OWthqeeloCizfofdF+tm7dmumxpuFp8+fPT12mwinr1q1zPZ2nS/OfAqlNgZ+N3ncN1fvrX/8a9L6r51HHfWbveyB95vrsdUyqJ0xDO/W+a2iceuT8c6b0t/P777+74009uF9//XW6fWm+ln/om2h7FcfQ35x6vfxtVK+wjv+NGzemG2KXlnqANDxRQ2ID50CpJ009k9k9RlRh8sMPPwy6BVLvbeDfT26Ozaw+MwAFA8MCAeQbOoFSCXYNidMwPp04+k/IdCKnkKIglZG0Q4sUyLI7GV8n4XoenZgGUnDT0KG0J+lpq5YFOuuss4Lu6wRaFBjTLtcJr0KTf9ijhitpaNvKlStdAY5A2s6/r4yeRzQ0LnC+joaI6YQ5M3pfNWww8KQ6o0IUGfG/L4HDIv10AqsglFMa6qnXntE+FQL1nimU+oc+ZvRe6H2QzOYu6fPW0D8N9fIXO1HQ0om4f/5Qbmkfad/PtJ+N3nd9pppfl9P3PZACtEKKjn/Np0s73FJDXTW8TfOmUlJSMj2G0y7T0FP9zWkorm6naqf+1nJ6jOhvU+E5swAcSHMLMytokbbtOT02s/OZASgYCFcA8o3MTqB0Uq3eiffeey9ojoxf2gu35qZ6X3ZLV2e274zaltlynbz6g5CKNujET/OAFMZ0AqpeNc1/0uvPyf6yS/tt3Lixe86MpA2F4Si374V6GXVBac0r07ykV155xRUKCQyxXrYn7fuuYBXYcxboVGE3Lc13Cpx7FEjFXzQPT72A999/v3s+f7EO/9yszI5r/zGneUyn6qlN+4VEqJxutc7sfGYACgbCFYACQd/I62RZ31Crd8tLNWvWdCeS6k3wT8IXTYBXRTOtz2sqXqGJ+Co2EdgTk93hYad6zzTULattvv32WxfscnpdJP/7ogIF/mGEflqWm/dNoUK9SHp8Wup9UY+TV4FPFSWbN2/uAo56fbZt2+YKkGTFi+tH6X3XkDkVi8irMv7//ve/Xe+QhtQGtlm9o9nhH5apXrGsrk12qvck8BgJHOapoYIq4JFX1zzLi2PzTF43DEDoMOcKQIGg6lz6dllVx9L2SOi+5oHkVteuXd1PVZkL5O/N0TyNvOb/5jzwtWnYmCq45ZaGBCo4pa12GPg8mk+jeTOzZ89Ot82RI0dc2fpTUS+jekNmzpwZVLZdvYsaapib903vQ6dOndy1zVT5LzDoqmfpggsucMPgvHLTTTe5OV767DU8UxUms+K/oPXplBLX+655Yapyl5bmRXlRpjyjY0pVMDXsNDv02apCoyo17tq1K936wHL3qiIoadut8KQeWFUSDGyHqhbq+M6rv628ODa9+NwBhD96rgAUCPqm/9FHH7URI0a4k24NddJ1pPTtt8KDihpo+FJuqOiDJsSrVLhOnFREQqWqNV9Fz6Nr9+Q1BQqdhF555ZWuMIHKqCvw6AQxoxPb7NBQMPVeaA6RCmqoWIKKFKh3TCedet0KFyqtrcn86iVTT4pO+tVLpOX+63llRD0akydPdoVD9J5paJ2/3LWuq6Xra+WGPmcVLFCQUkECzcHTCb5Okh977DHzkopkqNy7jiGV2c5OWXD1NKmgiEq5qxdVJcvVC6Zbdun90uesIXrffPON+/z13Oo9VbELvYcqtX86NMRRvVYqaKIwob8Vfe5qu46v7M6D1OegoaMqQqHeJ33GCmgq56/wLirrrjCn40GhSQVl/Nds09+svhT529/+5sr+q+dI171SiXQvioecqWPTi88dQPgjXAEoMHSdHZ3UaA6STtZEQ8R0YqqTttOh6wHpxFHXxtGJtopZ6KQwu0OoTpcm3isI6UKoCol6fv/1ddJWGswuzUP77LPP3GvQa1JY1MmuhgBqGJxomJ3mHOk91UWItZ2+odd7oYvsZjUEU3N6tP2kSZNs2LBhqRfx1Ylt4HWEckLFKtRuvf8KHxqyqeqKmkOU9hpXp0uFU3T8aG6bgmZOjhddX0sn6Rripvc4pyfZCjoKvAqOuj6UQqRO/BU4FHJPlz6b3bt3u/0rJCsY6D1UeAu8wG9m9BhV3tPfm/421EOsY0jDKQOv0abjVa9Hn5euvaaArrCubXWdKx3HuoaX3i+FEn0ZMmHChFxdyysnr9/rY9OLzx1AeCukeuyhbgQAAJFKJ9y6cLKq4wEACjbmXAEAkEsacqlrHuWk1woAkH8xLBAAgBzS/CNdV0zDvDQ0TfOfAACg5woAgBxaunSp661SyNJcNM0ZAgCAOVcAAAAA4AF6rgAAAADAA4QrAAAAAPAABS0yoGui7Ny5011gtFChQqFuDgAAAIAQ0SyqP//806pWrequ75gZwlUGFKx0YVEAAAAAkO3bt1v16tUtM4SrDKjHyv8GxsbGhro5AAAAAEIkKSnJdbz4M0JmCFcZ8A8FVLAiXAEAAAAolI3pQhS0AAAAAAAPEK4AAAAAwAOEKwAAAADwAHOuTqMk4/Hjx+3EiROhbgpCrEiRIla0aFHK9gMAABRwhKtcSE5Otl27dtnhw4dD3RSEiRIlSliVKlUsKioq1E0BAABAiBCucnGB4S1btrjeCl1ITCfT9FgU7B5Mhe29e/e646JevXpZXlwOAAAA+RPhKod0Iq2ApVr36q0AYmJirFixYrZ161Z3fERHR4e6SQAAAAgBvmLPJXonEIjjAQAAAJwRAgAAAIAHCFcAAAAA4AHmXAEAAAAIGwcOJ1viwWRLOppisTHFLL5klJUpERkVmem5KkBuvvlmV9lQN1U5rFu3ro0bN85drysvvfTSSxYXF+fJvmrVqpX6Gvy36tWrW1769NNP3fPs378/T58HAACgoNu5/4gNfHWtXTZlqXV/9nO77MmlNujVtW55JCBcFTB/+9vf3DW6Nm7caEOHDrUxY8bY448/nqt96QLKqpx4pikQ6jX4b2vXrs1wu5SUlDPeNgAAAOS+x2pYwjr7bGNi0PJlGxNteMI6tz7cEa5CSAfIz3sO2tptf9jPew+ekQOmePHiVrlyZatZs6bdcccd1rFjR3vrrbfcuilTpljjxo2tZMmSrtT8nXfeaQcPHkzXA6XtGzZs6Pa1bds2O3bsmN13331WrVo199g2bdq43h7Rz759+9qBAwdSe5oU6OSPP/6w3r17W9myZV1Z+y5durjQl5XSpUu71+C/VahQwS3Xvp977jm76qqrXDvGjx/vlmtZnTp1XG9d/fr1bd68eUH70+NeeOEF6969u2uHrlXlf09++eUXu+SSS9zvaqe2VQ8gAAAAvJV4MDldsAoMWFof7ghXBbzLU9do0rWZ/OXEn376afvvf/9rL7/8sn388cf2wAMPBG1/+PBhmzx5sgsj2q5ixYo2cOBAW7lypb322mu2bt06u/baa10PmYJSu3btbOrUqRYbG5va06QgJgopX331lQsyerwuyNu1a9fT6nFScFNI+u6776xfv372xhtv2D333ON66b7//nu7/fbbXdj75JNPgh43duxYu+6661z71YZevXrZ77//7kJmQkKC22bDhg2u/dOmTct1+wAAAJAxzbHKzJ9ZrA8HhKsC2uWpIPPRRx/Z+++/b5deeqlbNnjwYNdLo3lNWvboo4/a66+/HvQ4BZ9nn33WhSb1AiUmJtrcuXPtX//6l1144YWuh0jh6YILLnDL1VtUpkwZ1+Pj72kqVaqUC14KVQppelzTpk1t/vz5tmPHDlu0aFGmbR82bJjbh/+mQOh3ww03uPB09tln21lnnWVPPPGEC3HqhTvnnHNsyJAhds0117jlgbRNz5493Ty0CRMmuB671atXW5EiRaxcuXJuGwVJtV+vBwAAAN6KjS6W6frSWawPB1QLDNMuz7yqiPL222+7QKKQpPlSCiP+YXoKWxMnTrQff/zRkpKSXKGLo0ePut4qDZcThaUmTZqk7k89RJp7peASSEMFy5cvf8p2/PDDD1a0aFE3hNBP2yuwaV1m7r///qChefHx8am/t2zZMt3z3HbbbUHL2rdvn673KfA1aUihetr27NmTaTsAAADgnfhSUdahXrw7H05Ly7U+3BGuCliXp3qmNAdJIalq1aou4PjnFl1xxRVuHpbmKqm3Zvny5XbLLbe4YYP+cKVhhOqF8lMPj3p31qxZ434GUojLCwpT6mHKiIJRbhQrFvxNiF5jKIp1AAAAFFRlSkTZpB5N3EiuwIClYDW5R5OIKMdOuCpgXZ4KHxkFE4UjhYknn3zSzb2StEMCM9K8eXPXc6VeHg3vy4iCnLYJdO6557qesVWrVrkhhrJv3z43r0nFMryi51mxYoX16dMndZnu5+Q51H5J+xoAAADgrapxMTa9Z3M3kksdDjovVo9VJAQrIVyFQDh2eSpwaajg9OnT7corr3QBZObMmVk+TsMBVfxBVf8UzBS29u7da0uWLHFD7S6//HI3h0s9XFqmuVX+inzdunWz/v3726xZs1wFwOHDh7uKg1ruFQ0hVKEKtUuVEf/zn//YwoUL3RDI7FJlRfVkaUilil2o9y6veuUAAAAKujIlIidMpUVBixB2eSpIBQpll6dCj0qxqxLgeeed54pLaP5VdqhwhcKVKvJpztTVV19tX375pSsoIeqZGjBggF1//fWubPpjjz2W+rgWLVq44Yht27Z1RTbefffddEP0TofaovlVKmDRqFEjF+T0vBdffHG296HAp2qCCn+VKlVy1REBAACAtAr5dEaLICrmoIpwujaTChsEUoGHLVu2WO3atS06Ovq0nkdVASO1yxOWZ8cFAAAAIiMbpMWwwBCK5C5PAAAAAMEYFggAAAAAHiBcAQAAAIAHCFcAAAAA4AHCVS5RBwSBOB4AAABAuMohf5nww4cPh7opCCP+48HLMvIAAACILFQLzKEiRYpYXFyc7dmzx93XBXF1gVkU3B4rBSsdDzoudHwAAACgYCJc5ULlypXdT3/AAhSs/McFAAAACibCVS6op6pKlSpWsWJFS0lJCXVzEGIaCkiPFQAAAAhXp0En1JxUAwAAABAKWgAAAACABwhXAAAAAOABwhUAAAAAeIBwBQAAAAAeIFwBAAAAgAeoFggAAAAgbBw4nGyJB5Mt6WiKxcYUs/iSUVamRJRFAsIVAAAAgLCwc/8RG5awzj7bmJi6rEO9eJvUo4lVjYuxcMewQAAAAABh0WM1LE2wkmUbE214wjq3PtwRrgAAAACEXOLB5HTBKjBgaX24I1wBAAAACLmkoymZrv8zi/XhgHAFAAAAIORio4tlur50FuvDAeEKAAAAQMjFl4pyxSsyouVaH+4IVwAAAABCrkyJKFcVMG3A0v3JPZpERDl2SrEDAAAACAtV42Jses/mrniF5lhpKKB6rCIhWIVNz9WMGTOsVq1aFh0dbW3atLHVq1efctuUlBQbN26c1alTx23ftGlTW7x48Sm3nzRpkhUqVMgGDx6cR60HAAAA4BUFqToVS1mzs8q6n5ESrMIiXC1YsMCGDBlio0ePtq+//tqFpc6dO9uePXsy3P6hhx6yWbNm2fTp0239+vU2YMAA6969u61duzbdtl9++aXbtkmTJmfglQAAAAAoyEIerqZMmWL9+/e3vn37WsOGDW3mzJlWokQJmzNnTobbz5s3z0aOHGldu3a1s88+2+644w73+5NPPhm03cGDB61Xr142e/ZsK1u27Bl6NQAAAAAKqpCGq+TkZFuzZo117Njxfw0qXNjdX7lyZYaPOXbsmBsOGCgmJsaWL18etOyuu+6yyy+/PGjfp6J9JiUlBd0AAAAAIGLCVWJiop04ccIqVaoUtFz3d+/eneFjNGRQvV0bN260kydP2ocffmgLFy60Xbt2pW7z2muvuSGGEydOzFY7tF2ZMmVSbzVq1DjNVwYAAACgoAn5sMCcmjZtmtWrV88aNGhgUVFRNnDgQDekUD1esn37drvnnnts/vz56Xq4TmXEiBF24MCB1Jv2AQAAAAARE67i4+OtSJEi9ttvvwUt1/3KlStn+JgKFSrYokWL7NChQ7Z161b78ccfrVSpUm7+lWiYoYphnH/++Va0aFF3W7p0qT399NPud/WUpVW8eHGLjY0NugEAAABAxIQr9Ty1aNHClixZkrpMQ/10v23btpk+Vr1S1apVs+PHj1tCQoJ169bNLb/sssvsu+++s2+++Sb11rJlS1fcQr8rzAEAAABAvruIsMqw9+nTxwWg1q1b29SpU12vlIb6Se/evV2I8s+fWrVqle3YscOaNWvmfo4ZM8YFsgceeMCtL126tJ133nlBz1GyZEkrX758uuUAAAAAkG/C1fXXX2979+61UaNGuSIWCk26KLC/yMW2bdtS51PJ0aNH3bWuNm/e7IYDqgy7yrPHxcWF8FUAAAAgIwcOJ1viwWRLOppisTHFLL5kVERdFBbIiUI+n8+Xo0cUACrFrqqBKm7B/CsAAIDc2bn/iA1LWGefbUxMXdahXrxN6tHEqsbFhLRtQF5kg4irFggAAIDI6LFKG6xk2cZEG56wzq0H8hvCFQAAADynoYBpg1VgwNJ6IL8hXAEAAMBzmmOVmT+zWA9EIsIVAAAAPBcbXSzT9aWzWA9EIsIVAAAAPBdfKsoVr8iIlms9kN8QrgAAAOA5lVtXVcC0AUv3J/doQjl25Eshv84VAAAA8ieVW5/es7krXqE5VhoKqB4rghXyK8IVAAAA8oyCFGEKBQXDAgEAAADAA4QrAAAAAPAA4QoAAAAAPEC4AgAAAAAPEK4AAAAAwAOEKwAAAADwAOEKAAAAADxAuAIAAAAADxCuAAAAAMADRb3YCQAAAJCRA4eTLfFgsiUdTbHYmGIWXzLKypSICnWzgDxBuAIAAECe2Ln/iA1LWGefbUxMXdahXrxN6tHEqsbFhLRtQF4gXAEAACBPeqxGvfm9Na0RZze3q2XHjp+06GJF7Ottf9joN7+3J65tSg8W8h3CFQAAADy371Cy/b31WTZ3xRZ75uNNqcvb1y1vfdvXdusJV8hvKGgBAAAAzx0/6XPBasWmfUHLdV/LT5z0haxtQF4hXAEAAMBzJ0/60gUrPy0nXCE/IlwBAADAc4eTj2ex/sQZawtwpjDnCgAKMEokA8grZWIy/7ekTEyxM9YW4EwhXAFAAUWJZAB5Kb5UlPs3ZVnAvzF+Wq71QH7DsEAAKKA9VmmDlegkaHjCOrceAE6HesH1ZY2CVCDdn9yjCb3kyJfouQKAAkhDAdMGq8CApfWc+AA4XeoFn96zufs35c+jKVY6upjrseLfF+TXIeuEKwAogPQ/rMzoJAgAvKCT4kg5MUbo7YzwIesMCwSAAig2OvOJ5Pp2GQCAM+lAPhiyTrgCgAI80TwjTDQHAITrkPVwR7gCgAKIieYAgHCTlA+GrDPnCgAKKCaaAwDCSWw+GLJOuAKAAoyJ5gCAcBGfD66NxrBAAAAAACFXJh8MWafnCgAAAEBYqBrhQ9YJVwAAAADCRpkIHrLOsEAAAAAA8AA9VwBQgOmCjBp6ofK3sTHFLL5k5H5bCABAqBGuAKCA2rn/iA1LWBd0wUZNGtZkYo15BwAAOcOwQAAooD1WaYOVqPzt8IR1bj0AAMgZwhUAFEAaCpg2WAUGLK0HAAA5Q7gCgAJIc6wyo/K3AAAgZwhXAFAAxUYXy3S9risCAAByhnAFAAWQLsio4hUZ0XKtBwAAOUO4AoACSOXWH736PLugbvmg5bqv5ZRjBwAg5yjFDgAFkKoBjnt7vTU7q6z1bV/bjh0/acWLFra12/fbI2+vtyeubUrAAgAghwhXAFAAqRrgRz/scbdTrSdcAQCQMwwLBIACiGqBAAB4j3AFAAUQ1QIBAPAe4QoACiCqBQIA4D3CFQAUQJpPNalHk3QBS/cn92jCfCsAAHKBghYAUEBVjYux6T2bu+IVmmOloYDqsSJYAQCQO4QrACjAFKQIUwAAeINhgQAAAADgAcIVAAAAAHiAcAUAAAAAHiBcAQAAAIAHCFcAAAAA4AHCFQAAAAB4gHAFAAAAAB4gXAEAAACABwhXAAAAAOABwhUAAAAAeIBwBQAAAAAeIFwBAAAAgAcIVwAAAADgAcIVAAAAAHiAcAUAAAAAHiBcAQAAAEB+CVczZsywWrVqWXR0tLVp08ZWr159ym1TUlJs3LhxVqdOHbd906ZNbfHixUHbTJw40Vq1amWlS5e2ihUr2tVXX20bNmw4A68EAAAAQEEV8nC1YMECGzJkiI0ePdq+/vprF5Y6d+5se/bsyXD7hx56yGbNmmXTp0+39evX24ABA6x79+62du3a1G2WLl1qd911l33xxRf24YcfukDWqVMnO3To0Bl8ZQAAAAAKkkI+n88Xygaop0q9TM8884y7f/LkSatRo4YNGjTIhg8fnm77qlWr2oMPPujCk1+PHj0sJibG/vnPf2b4HHv37nU9WApdHTp0yLJNSUlJVqZMGTtw4IDFxsae1usDAAAAELlykg1C2nOVnJxsa9assY4dO/6vQYULu/srV67M8DHHjh1zwwEDKVgtX778lM+jN0LKlSt3yn3qTQu8AQAAAEBOhDRcJSYm2okTJ6xSpUpBy3V/9+7dGT5GQwanTJliGzdudL1cGva3cOFC27VrV4bba5vBgwdb+/bt7bzzzstwG83RUhr139RzBgAAAAARNecqp6ZNm2b16tWzBg0aWFRUlA0cOND69u3rerwyouGD33//vb322mun3OeIESNc75b/tn379jx8BQAAAADyo5CGq/j4eCtSpIj99ttvQct1v3Llyhk+pkKFCrZo0SJXnGLr1q32448/WqlSpezss89Ot62C19tvv22ffPKJVa9e/ZTtKF68uBs/GXgDAAAAgIgJV+p5atGihS1ZsiRoGJ/ut23bNtPHat5VtWrV7Pjx45aQkGDdunVLXacaHQpWb7zxhn388cdWu3btPH0dAAAAAFA01A1QGfY+ffpYy5YtrXXr1jZ16lTXK6WhftK7d28XojQvSlatWmU7duywZs2auZ9jxoxxgeyBBx4IGgr4yiuv2JtvvumudeWfv6X5VCp+AQAAAAD5Llxdf/31rlT6qFGjXAhSaNJFgf1FLrZt2xY0n+ro0aPuWlebN292wwG7du1q8+bNs7i4uNRtnnvuOffz4osvDnquuXPn2s0333zGXhsAAACAgiPk17kKR1znCgAAAEBEXecKAAAAAPILwhUAAAAAeIBwBQAAAAAeIFwBAAAAgAcIVwAAAADgAcIVAAAAAIQ6XCUnJ9uGDRvs+PHjXrQFAAAAAApWuDp8+LDdcsstVqJECWvUqJG70K8MGjTIJk2a5HUbAQAAACB/hqsRI0bYt99+a59++qlFR0enLu/YsaMtWLDAy/YBAAAAQEQompsHLVq0yIWov/zlL1aoUKHU5erF+vnnn71sHwAAAADk356rvXv3WsWKFdMtP3ToUFDYAgAAAICCIlfhqmXLlvbOO++k3vcHqhdeeMHatm3rXesAAAAAID8PC5wwYYJ16dLF1q9f7yoFTps2zf3++eef29KlS71vJQAAAADkx56rCy64wBW0ULBq3LixffDBB26Y4MqVK61FixbetxIAAAAA8lvPVUpKit1+++328MMP2+zZs/OmVQAAAACQ33uuihUrZgkJCXnTGgAAAAAoSMMCr776aleOHQAAAABwGgUt6tWrZ+PGjbMVK1a4OVYlS5YMWn/33XfnZrcAAAAAELEK+Xw+X04fVLt27VPvsFAh27x5s0WypKQkK1OmjB04cMBiY2ND3RwAAAAAEZANctVztWXLlty2DQAAAADypVzNuQqkjq9cdH4B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whUAAAAAeIBwBQAAAAAeIFwBAAAAgAcIVwAAAADgAcIVAAAAAOSHcDVjxgyrVauWRUdHW5s2bWz16tWZbj916lSrX7++xcTEWI0aNezee++1o0ePpq4/ceKEPfzww1a7dm23TZ06deyRRx4xn893Bl4NAAAAgIKqaCiffMGCBTZkyBCbOXOmC1YKTp07d7YNGzZYxYoV023/yiuv2PDhw23OnDnWrl07++mnn+zmm2+2QoUK2ZQpU9w2kydPtueee85efvlla9SokX311VfWt29fK1OmjN19990heJUAAAAACoJCvhB26ShQtWrVyp555hl3/+TJk643atCgQS5EpTVw4ED74YcfbMmSJanLhg4daqtWrbLly5e7+1dccYVVqlTJXnzxxdRtevTo4Xqx/vnPf2arXUlJSS6MHThwwGJjYz14pQAAAAAiUU6yQciGBSYnJ9uaNWusY8eO/2tM4cLu/sqVKzN8jHqr9Bj/0MHNmzfbu+++a127dg3aRuFLvVry7bffuuDVpUuXU7bl2LFj7k0LvAEAAABARAwLTExMdPOj1MsUSPd//PHHDB9zww03uMddcMEFbg7V8ePHbcCAATZy5MjUbdTjpXDUoEEDK1KkiHuO8ePHW69evU7ZlokTJ9rYsWM9fHUAAAAACpqQF7TIiU8//dQmTJhgzz77rH399de2cOFCe+edd1zBCr/XX3/d5s+f7+ZnaRvNvXriiSfcz1MZMWKE6+bz37Zv336GXhEAAACA/CJkPVfx8fGuZ+m3334LWq77lStXzvAxqgJ400032a233uruN27c2A4dOmS33XabPfjgg25Y4f333+96r/7+97+nbrN161bXO9WnT58M91u8eHF3AwAAAICI67mKioqyFi1aBBWnUEEL3W/btm2Gjzl8+LALUIEU0MRfl+NU22jfAAAAAJAvS7GrDLt6k1q2bGmtW7d2pdjVE6XS6dK7d2+rVq2a63WSK6+80pVcb968uas0uGnTJtebpeX+kKXfNcfqrLPOcqXY165d6x7Tr1+/UL5UAAAAAPlcSMPV9ddfb3v37rVRo0bZ7t27rVmzZrZ48eLUIhfbtm0L6oV66KGH3DWt9HPHjh1WoUKF1DDlN336dBe47rzzTtuzZ49VrVrVbr/9dvccAAAAAJAvr3MVrrjOFQAAAICIuc4VAAAAAOQnhCsAAAAA8ADhCgAAAAA8QLgCAAAAAA8QrgAAAADAA4QrAAAAAPAA4QoAAAAAPEC4AgAAAAAPEK4AAAAAwAOEKwAAAADwAOEKAAAAADxAuAIAAAAADxCuAAAAAMADhCsAAAAA8ADhCgAAAAA8QLgCAAAAAA8QrgAAAADAA4QrAAAAAPAA4QoAAAAAPEC4AgAAAAAPEK4AAAAAwAOEKwAAAADwAOEKAAAAADxAuAIAAAAADxCuAAAAAMADhCsAAAAA8ADhCgAAAAA8QLgCAAAAAA8QrgAAAADAA4QrAAAAAPAA4QoAAAAAPEC4AgAAAAAPFPViJ8gbBw4nW+LBZEs6mmKxMcUsvmSUlSkRFepmAQAAAMgA4SpM7dx/xIYlrLPPNiamLutQL94m9WhiVeNiQto2AAAAAOkxLDBMe6zSBitZtjHRhiesc+sBAAAAhBfCVRjSUMC0wSowYGk9AAAAgPBCuApDmmOVmT+zWA8AAADgzCNchaHY6GKZri+dxXoAAAAAZx7hKgzFl4pyxSsyouVaDwAAACC8EK7CkMqtqypg2oCl+5N7NKEcOwAAABCGKMUeplRufXrP5q54heZYaSigeqwIVgAAAEB4IlyFMQUpwhQAAAAQGRgWCAAAAAAeIFwBAAAAgAcIVwAAAADgAcIVAAAAAHiAcAUAAAAAHiBcAQAAAIAHCFcAAAAA4AGucxXGDhxOdhcRTjqaYrExxSy+JNe9AgAAAMIV4SpM7dx/xIYlrLPPNiamLutQL94m9WhiVeNiQto2AAAAAOkxLDBMe6zSBitZtjHRhiesc+sBAAAAhBfCVRjSUMC0wSowYGk9AAAAgPBCuApDmmOVmT+zWA8AAADgzCNchaHY6GKZri+dxXoAAAAAZx7hKgzFl4pyxSsyouVaDwAAACC8EK7CkMqtqypg2oCl+5N7NKEcOwAAABCGKMUeplRufXrP5q54heZYaSigeqwIVgAAAEB4IlyFMQUpwhQAAAAQGRgWCAAAAAAeoOcqjOliwRoWqNLssTHFLL4kPVkAAABAuCJchamd+4/YsIR1QRcTVkELFbrQfCwAAAAA4YVhgWHaY5U2WMmyjYk2PGGdWw8AAAAgvBCuwpCGAqYNVoEBS+sBAAAAhBfCVRjSHKvMqDQ7AAAAgPBCuApDsdHFMl2va14BAAAACC+EqzCkiwWreEVGtFzrAQAAAIQXwlUYUrl1VQVMG7B0f3KPJpRjBwAAAMIQpdjDlMqtT+/Z3BWv0BwrDQVUjxXBCgAAAAhPhKswpiBFmAIAAAAiA8MCAQAAACA/hKsZM2ZYrVq1LDo62tq0aWOrV6/OdPupU6da/fr1LSYmxmrUqGH33nuvHT16NGibHTt22I033mjly5d32zVu3Ni++uqrPH4lAAAAAAqykA4LXLBggQ0ZMsRmzpzpgpWCU+fOnW3Dhg1WsWLFdNu/8sorNnz4cJszZ461a9fOfvrpJ7v55putUKFCNmXKFLfNH3/8Ye3bt7dLLrnE3nvvPatQoYJt3LjRypYtG4JXCAAAAKCgKOTz+XyhenIFqlatWtkzzzzj7p88edL1Rg0aNMiFqLQGDhxoP/zwgy1ZsiR12dChQ23VqlW2fPlyd1+PW7FihX322WfZbsexY8fczS8pKcm148CBAxYbG3uarxIAAABApFI2KFOmTLayQciGBSYnJ9uaNWusY8eO/2tM4cLu/sqVKzN8jHqr9Bj/0MHNmzfbu+++a127dk3d5q233rKWLVvatdde63q/mjdvbrNnz860LRMnTnRvmP+mYAUAAAAAORGycJWYmGgnTpywSpUqBS3X/d27d2f4mBtuuMHGjRtnF1xwgRUrVszq1KljF198sY0cOTJ1GwWu5557zurVq2fvv/++3XHHHXb33Xfbyy+/fMq2jBgxwiVR/2379u0evlIAAAAABUHIC1rkxKeffmoTJkywZ5991r7++mtbuHChvfPOO/bII4+kbqOhheeff77bTr1Wt912m/Xv39/N6zqV4sWLuy6+wBsAAAAARERBi/j4eCtSpIj99ttvQct1v3Llyhk+5uGHH7abbrrJbr31VndfVQAPHTrkAtSDDz7ohhVWqVLFGjZsGPS4c8891xISEvLw1QAAAAAo6ELWcxUVFWUtWrQIKk6hXifdb9u2bYaPOXz4sAtQgRTQxF+XQ5UCVW0wkKoK1qxZMw9eBQAAAACEQSl2lWHv06ePK0DRunVrV4pdPVF9+/Z163v37m3VqlVzBSfkyiuvdCXXNdxPlQY3bdrkerO03B+ydN0rFb7QsMDrrrvOFb94/vnn3Q0AAAAA8mW4uv76623v3r02atQoV8SiWbNmtnjx4tQiF9u2bQvqqXrooYfcNa30UxcK1jWsFKzGjx+fuo1Ku7/xxhuuSIWKX9SuXduFtl69eoXkNQIAAAAoGEJ6natwpYqBcXFxrmogxS0AAACAgivp/10Dd//+/e6yTWHbcxWu/vzzT/eT610BAAAA8GeErMIVPVcZUGGNnTt3WunSpd0wxHBIyvSiIbs4ZpBTHDPIKY4Z5BTHDCL5mFFcUrCqWrVquuJ6adFzlQG9adWrV7dwwvW3kFMcM8gpjhnkFMcMcopjBpF6zGTVYxWRFxEGAAAAgHBFuAIAAAAADxCuwlzx4sVt9OjR7ieQHRwzyCmOGeQUxwxyimMGBeWYoaAFAAAAAHiAnisAAAAA8ADhCgAAAAA8QLgCAAAAAA8QrgAAAADAA4SrMLZs2TK78sor3dWgCxUqZIsWLQp1kxDGJk6caK1atbLSpUtbxYoV7eqrr7YNGzaEulkIY88995w1adIk9QKNbdu2tffeey/UzUKEmDRpkvt/0+DBg0PdFISxMWPGuOMk8NagQYNQNwthbMeOHXbjjTda+fLlLSYmxho3bmxfffWVRQrCVRg7dOiQNW3a1GbMmBHqpiACLF261O666y774osv7MMPP7SUlBTr1KmTO46AjFSvXt2dIK9Zs8b9j+vSSy+1bt262X//+99QNw1h7ssvv7RZs2a5cA5kpVGjRrZr167U2/Lly0PdJISpP/74w9q3b2/FihVzX/atX7/ennzySStbtqxFiqKhbgBOrUuXLu4GZMfixYuD7r/00kuuB0snzh06dAhZuxC+1DMeaPz48a43SwFdJ0NARg4ePGi9evWy2bNn26OPPhrq5iACFC1a1CpXrhzqZiACTJ482WrUqGFz585NXVa7du2Qtimn6LkC8qkDBw64n+XKlQt1UxABTpw4Ya+99prr6dTwQOBU1EN++eWXW8eOHUPdFESIjRs3uikOZ599tgvm27ZtC3WTEKbeeusta9mypV177bXuC+LmzZu7L3IiCT1XQD508uRJNw9CXevnnXdeqJuDMPbdd9+5MHX06FErVaqUvfHGG9awYcNQNwthSgH866+/dsMCgexo06aNG0lRv359NyRw7NixduGFF9r333/v5ggDgTZv3uxGUAwZMsRGjhzp/q25++67LSoqyvr06WORgHAF5NNvlvU/Lsa1Iys64fnmm29cT+e///1v9z8vzd8jYCGt7du32z333OPmdEZHR4e6OYgQgdMbNEdPYatmzZr2+uuv2y233BLStiE8vxxu2bKlTZgwwd1Xz5XOZ2bOnBkx4YphgUA+M3DgQHv77bftk08+cQULgMzo28C6detaixYtXMVJFdGZNm1aqJuFMKT5m3v27LHzzz/fzaHRTUH86aefdr9raCmQlbi4ODvnnHNs06ZNoW4KwlCVKlXSfbl37rnnRtRQUnqugHzC5/PZoEGD3LCuTz/9NOImgCJ8vjU8duxYqJuBMHTZZZe5YaSB+vbt68pqDxs2zIoUKRKytiGyCqL8/PPPdtNNN4W6KQhD7du3T3cZmZ9++sn1dkYKwlWY/wMU+M3Oli1b3PAdFSg466yzQto2hOdQwFdeecXefPNNN4599+7dbnmZMmXcdSKAtEaMGOGG7Ojfkz///NMdPwrm77//fqibhjCkf1fSzuEsWbKkuxYNcztxKvfdd5+rTKqT4507d9ro0aNdEO/Zs2eom4YwdO+991q7du3csMDrrrvOVq9ebc8//7y7RQrCVRjTdWcuueSS1Pua3Ccac6rJoUAgTQCViy++OGi5ypnefPPNIWoVwpmGePXu3dtNMlcI13wIBau//vWvoW4agHzi119/dUFq3759VqFCBbvgggvc5R70O5BWq1at3Agcffk3btw4Nwpn6tSprspkpCjk01giAAAAAMBpoaAFAAAAAHiAcAUAAAAAHiBcAQAAAIAHCFcAAAAA4AHCFQAAAAB4gHAFAAAAAB4gXAEAAACABwhXAAAAAOABwhUAIJ1ffvnFChUqZN98842Fix9//NH+8pe/WHR0tDVr1qxAvOactO3w4cPWo0cPi42Nddvu37//jLYRAEC4AoCwdPPNN7sT5EmTJgUtX7RokVteEI0ePdpKlixpGzZssCVLlli4O9Nh7eWXX7bPPvvMPv/8c9u1a5eVKVPGk/1efPHFNnjwYE/2BQD5HeEKAMKUemgmT55sf/zxh+UXycnJuX7szz//bBdccIHVrFnTypcv72m78gO9P+eee66dd955Vrly5bAL4afz2QNApCBcAUCY6tixoztJnjhx4im3GTNmTLohclOnTrVatWoF9YJdffXVNmHCBKtUqZLFxcXZuHHj7Pjx43b//fdbuXLlrHr16jZ37twMh+K1a9fOBT2dtC9dujRo/ffff29dunSxUqVKuX3fdNNNlpiYGNTrMXDgQNfzER8fb507d87wdZw8edK1Se0oXry4e02LFy9OXa+gsGbNGreNftfrzsi///1va9y4scXExLgApvfw0KFDqetfeOEFF0D0eho0aGDPPvvsKd/b7Lw+tfuxxx6zunXrunafddZZNn78eLeudu3a7mfz5s1dm/VeZLcdq1evdo/T+pYtW9ratWszbaf2/eSTT9qyZcuCnuvYsWN23333WbVq1VyvX5s2bezTTz9Nfdy+ffusZ8+ebn2JEiXce/fqq68GHTv6zKdNm+b2q5t65F566SV3HGXWq+o/NvVa9V7otYiGK956661WoUIFN4Tx0ksvtW+//Tb1cfr9kksusdKlS7v1LVq0sK+++irT1w8A4YJwBQBhqkiRIi4QTZ8+3X799dfT2tfHH39sO3fudCffU6ZMcUPsrrjiCitbtqytWrXKBgwYYLfffnu651H4Gjp0qDu5b9u2rV155ZXuhNx/kqwTY4UAnfwqDP3222923XXXpRuuFhUVZStWrLCZM2dm2D6dvCscPPHEE7Zu3ToXwq666irbuHGjW69hbo0aNXJt0e8KDGlpuYJCv3797IcffnAh4pprrjGfz+fWz58/30aNGuXCj9brvX344Ydd+zKSndc3YsQIN3RT+1m/fr298sorLoT5A5J89NFHrm0LFy7MVjsOHjzoPpuGDRu6QKmQktHrDaR99+/f331Ggc+lYLty5Up77bXX3Pt67bXX2t/+9rfU9/Xo0aMuvLzzzjsuSN52220uQPrbrs9F+9S+tV/datSoYdm1adMmS0hIcO3xD49UG/bs2WPvvfeee33nn3++XXbZZfb777+79b169XIh+8svv3Trhw8fbsWKFcv2cwJASPkAAGGnT58+vm7durnf//KXv/j69evnfn/jjTeUFFK3Gz16tK9p06ZBj33qqad8NWvWDNqX7p84cSJ1Wf369X0XXnhh6v3jx4/7SpYs6Xv11Vfd/S1btrjnmTRpUuo2KSkpvurVq/smT57s7j/yyCO+Tp06BT339u3b3eM2bNjg7l900UW+5s2bZ/l6q1at6hs/fnzQslatWvnuvPPO1Pt6nXq9p7JmzRr33L/88kuG6+vUqeN75ZVXgpbpNbRt2zboNa9duzZbry8pKclXvHhx3+zZszN8vrT7y247Zs2a5StfvrzvyJEjqeufe+65DPcV6J577nHvt9/WrVt9RYoU8e3YsSNou8suu8w3YsSIU+7n8ssv9w0dOjT1vvapfQeaO3eur0yZMkHLMjo2ixUr5tuzZ0/qss8++8wXGxvrO3r0aLr3RK9bSpcu7XvppZdO2T4ACGdFQxvtAABZ0bwr9aBk1XuRGfX6FC78v8EK6l3RML/AXjINo1OPQiD1WvgVLVrUDVFTb4t/+NYnn3zihsxlNP/nnHPOcb+rZyQzSUlJrletffv2Qct1P3C4WFaaNm3qekA0tE09X506dbL/+7//c71zGhqoNt1yyy2uF8ZPQyNPVfghq9enni0Nu9NzZld22qH3t0mTJqnD6NJ+Dtn13Xff2YkTJ1I/Bz+12T9nTevVc/b666/bjh073LwordcQQS9ofpyG/wW+p+qZSztn7siRI+59kSFDhrhhg/PmzXPDOtXTVadOHU/aAwB5jXAFAGGuQ4cOLixoCJrmwARSYPIPe/NLSUlJt4+0w6o0NyajZZpDlF06SdYwQYW/tKpUqZL6u+b6nAkKiB9++KGrlvfBBx+44ZQPPvigG/boDwuzZ892847SPi43r2/z5s05bqP2mdN25JaeS/vU0Lq0+/YHxscff9wN/dM8PYVSfVaaH5dV8YnsHndpP3u1Se9d4LwvP/8cLg2DvOGGG9xQRQ0d1BBWDWvs3r17Dl49AIQG4QoAIoDm9ag4QP369YOWq1dg9+7d7kTXX0zAy9LfX3zxhQt3/t4VnahrHo9orozm06h4hnq1cktFC6pWrermZF100UWpy3W/devWOdqX3gP1eOmmeU3qOXnjjTdcb4ieQ4FIc3qyI6vXV69ePVc4Q2Xh1dOSluaZ+XuHAnsMs2qHCl2o10bzofy9V/occkpzxfTc6o288MILM9xG73G3bt3sxhtvdPcVrn/66Sc33yvwdQS+Bv9x9+eff7qeOH+Ays5xp/dUx6vez8CiK2mpt023e++9182jU7EVwhWASEBBCwCIAOpV0Mn4008/HbRcVeH27t3rKtZpWNWMGTPct/1e0f4UTlQ18K677nJl4VUwQnRfRQh08qviA3r+999/3/r27ZvuZDwrKpyhHqIFCxa461ipiIFO1u+5555s70M9VBripuIT27Ztc0UU9N4orMjYsWNd5UW9hwoQGjank3YV+MhIVq9PwWfYsGH2wAMP2D/+8Q+3XiHoxRdfdI+vWLGiC1/+QhgHDhzIVjvUa6OQqGGDKpLx7rvvukIfOaVwomOmd+/e7r3YsmWLK1Sh51avkD8g+nv7NBxRRU3U1kAKQXpvVSVQlRIVwNTrpt7AkSNHutetQh6qIJgVDfPTEEdVr1Tvovap51YPoz43DQ9UeFfP1tatW13403vv/wwBIOyFetIXACDzghaBBRKioqKCigb4ix3UqFHDFaTo3bu3KwyRtqBF2n1lVKRAj1ExDP9z6XlUeKF169bueRs2bOj7+OOPgx7z008/+bp37+6Li4vzxcTE+Bo0aOAbPHiw7+TJk6d8noyo2MaYMWN81apVc0UQVLzivffeC9omq4IW69ev93Xu3NlXoUIFV2jinHPO8U2fPj1om/nz5/uaNWvmXk/ZsmV9HTp08C1cuDDoNQcWjcjq9andjz76qHvv1O6zzjrLN2HChNTHq9iFPpvChQsHFZvIrB2ycuVK93q1XtslJCTkuKCFJCcn+0aNGuWrVauWa1+VKlXc61m3bp1bv2/fPndslCpVylexYkXfQw895I6hwONFxTtUVEWvX23Q++QvYFG3bl23/IorrvA9//zzWRZbERUCGTRokCtiojbp/enVq5dv27ZtvmPHjvn+/ve/u2V67dpm4MCBQcU9ACCcFdJ/Qh3wAAAAACDSMSwQAAAAADxAuAIAAAAADxCuAAAAAMADhCsAAAAA8ADhCgAAAAA8QLgCAAAAAA8QrgAAAADAA4QrAAAAAPAA4QoAAAAAPEC4AgAAAAAPEK4AAAAAwE7f/wdcDPcsgq50CgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "df = est.evaluated_individuals\n",
    "col1 = \"Number of selected features\"\n",
    "col2 = \"roc_auc_score\"\n",
    "\n",
    "# Multiple orange dots show because the pareto front in this case is actually 3D along the auroc score, number of features, and complexity.\n",
    "\n",
    "#replace nans in pareto front with 0\n",
    "fig, ax = plt.subplots(figsize=(5,5))\n",
    "sns.scatterplot(df[df['Pareto_Front']!=1], x=col1, y=col2, label='other', ax=ax)\n",
    "sns.scatterplot(df[df['Pareto_Front']==1], x=col1, y=col2, label='Pareto Front', ax=ax)\n",
    "ax.title.set_text('Performance of all pipelines')\n",
    "#log scale y\n",
    "ax.set_yscale('log')\n",
    "plt.show()\n",
    "\n",
    "#replace nans in pareto front with 0\n",
    "fig, ax = plt.subplots(figsize=(10,5))\n",
    "sns.scatterplot(df[df['Pareto_Front']==1], x=col1, y=col2, label='Pareto Front', ax=ax)\n",
    "ax.title.set_text('Performance of only the Pareto Front')\n",
    "#log scale y\n",
    "# ax.set_yscale('log')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Other Examples\n",
    "\n",
    "As with all search spaces, GeneticFeatureSelectorNode can be combined with any other search space. \n",
    "\n",
    "You can also pair this with the existing prebuilt templates, for example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-2 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-2 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-2 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-2 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-2 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-2 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-2 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-2 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-2 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-2 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                 MaskSelector(mask=array([False, False,  True, False, False, False, False, False, False,\n",
       "        True, False, False]))),\n",
       "                (&#x27;pipeline&#x27;,\n",
       "                 Pipeline(steps=[(&#x27;normalizer&#x27;, Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                 (&#x27;selectpercentile&#x27;,\n",
       "                                  SelectPercentile(percentile=74.2561844719571)),\n",
       "                                 (&#x27;featureunion-1&#x27;,\n",
       "                                  FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                  FeatureUnion(transformer_list=[(&#x27;binarizer&#x27;,\n",
       "                                                                                                  Binarizer(threshold=0.0935770250992))])),\n",
       "                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                  Passthrough())])),\n",
       "                                 (&#x27;featureunion-2&#x27;,\n",
       "                                  FeatureUnion(transformer_list=[(&#x27;skiptransformer&#x27;,\n",
       "                                                                  SkipTransformer()),\n",
       "                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                  Passthrough())])),\n",
       "                                 (&#x27;adaboostclassifier&#x27;,\n",
       "                                  AdaBoostClassifier(algorithm=&#x27;SAMME&#x27;,\n",
       "                                                     learning_rate=0.9665397922726,\n",
       "                                                     n_estimators=320))]))])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-4\" type=\"checkbox\" ><label for=\"sk-estimator-id-4\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;&nbsp;Pipeline<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link \">i<span>Not fitted</span></span></label><div class=\"sk-toggleable__content \"><pre>Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                 MaskSelector(mask=array([False, False,  True, False, False, False, False, False, False,\n",
       "        True, False, False]))),\n",
       "                (&#x27;pipeline&#x27;,\n",
       "                 Pipeline(steps=[(&#x27;normalizer&#x27;, Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                 (&#x27;selectpercentile&#x27;,\n",
       "                                  SelectPercentile(percentile=74.2561844719571)),\n",
       "                                 (&#x27;featureunion-1&#x27;,\n",
       "                                  FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                  FeatureUnion(transformer_list=[(&#x27;binarizer&#x27;,\n",
       "                                                                                                  Binarizer(threshold=0.0935770250992))])),\n",
       "                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                  Passthrough())])),\n",
       "                                 (&#x27;featureunion-2&#x27;,\n",
       "                                  FeatureUnion(transformer_list=[(&#x27;skiptransformer&#x27;,\n",
       "                                                                  SkipTransformer()),\n",
       "                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                  Passthrough())])),\n",
       "                                 (&#x27;adaboostclassifier&#x27;,\n",
       "                                  AdaBoostClassifier(algorithm=&#x27;SAMME&#x27;,\n",
       "                                                     learning_rate=0.9665397922726,\n",
       "                                                     n_estimators=320))]))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-5\" type=\"checkbox\" ><label for=\"sk-estimator-id-5\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">MaskSelector</label><div class=\"sk-toggleable__content \"><pre>MaskSelector(mask=array([False, False,  True, False, False, False, False, False, False,\n",
       "        True, False, False]))</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-6\" type=\"checkbox\" ><label for=\"sk-estimator-id-6\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;pipeline: Pipeline<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for pipeline: Pipeline</span></a></label><div class=\"sk-toggleable__content \"><pre>Pipeline(steps=[(&#x27;normalizer&#x27;, Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                (&#x27;selectpercentile&#x27;,\n",
       "                 SelectPercentile(percentile=74.2561844719571)),\n",
       "                (&#x27;featureunion-1&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                 FeatureUnion(transformer_list=[(&#x27;binarizer&#x27;,\n",
       "                                                                                 Binarizer(threshold=0.0935770250992))])),\n",
       "                                                (&#x27;passthrough&#x27;,\n",
       "                                                 Passthrough())])),\n",
       "                (&#x27;featureunion-2&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;skiptransformer&#x27;,\n",
       "                                                 SkipTransformer()),\n",
       "                                                (&#x27;passthrough&#x27;,\n",
       "                                                 Passthrough())])),\n",
       "                (&#x27;adaboostclassifier&#x27;,\n",
       "                 AdaBoostClassifier(algorithm=&#x27;SAMME&#x27;,\n",
       "                                    learning_rate=0.9665397922726,\n",
       "                                    n_estimators=320))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-7\" type=\"checkbox\" ><label for=\"sk-estimator-id-7\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;Normalizer<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.Normalizer.html\">?<span>Documentation for Normalizer</span></a></label><div class=\"sk-toggleable__content \"><pre>Normalizer(norm=&#x27;l1&#x27;)</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-8\" type=\"checkbox\" ><label for=\"sk-estimator-id-8\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;SelectPercentile<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.feature_selection.SelectPercentile.html\">?<span>Documentation for SelectPercentile</span></a></label><div class=\"sk-toggleable__content \"><pre>SelectPercentile(percentile=74.2561844719571)</pre></div> </div></div><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-9\" type=\"checkbox\" ><label for=\"sk-estimator-id-9\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;featureunion-1: FeatureUnion<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.FeatureUnion.html\">?<span>Documentation for featureunion-1: FeatureUnion</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                FeatureUnion(transformer_list=[(&#x27;binarizer&#x27;,\n",
       "                                                                Binarizer(threshold=0.0935770250992))])),\n",
       "                               (&#x27;passthrough&#x27;, Passthrough())])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>featureunion</label></div></div><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>binarizer</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-10\" type=\"checkbox\" ><label for=\"sk-estimator-id-10\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;Binarizer<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.Binarizer.html\">?<span>Documentation for Binarizer</span></a></label><div class=\"sk-toggleable__content \"><pre>Binarizer(threshold=0.0935770250992)</pre></div> </div></div></div></div></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>passthrough</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-11\" type=\"checkbox\" ><label for=\"sk-estimator-id-11\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">Passthrough</label><div class=\"sk-toggleable__content \"><pre>Passthrough()</pre></div> </div></div></div></div></div></div></div><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-12\" type=\"checkbox\" ><label for=\"sk-estimator-id-12\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;featureunion-2: FeatureUnion<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.FeatureUnion.html\">?<span>Documentation for featureunion-2: FeatureUnion</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureUnion(transformer_list=[(&#x27;skiptransformer&#x27;, SkipTransformer()),\n",
       "                               (&#x27;passthrough&#x27;, Passthrough())])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>skiptransformer</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-13\" type=\"checkbox\" ><label for=\"sk-estimator-id-13\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">SkipTransformer</label><div class=\"sk-toggleable__content \"><pre>SkipTransformer()</pre></div> </div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>passthrough</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-14\" type=\"checkbox\" ><label for=\"sk-estimator-id-14\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">Passthrough</label><div class=\"sk-toggleable__content \"><pre>Passthrough()</pre></div> </div></div></div></div></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-15\" type=\"checkbox\" ><label for=\"sk-estimator-id-15\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;AdaBoostClassifier<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.ensemble.AdaBoostClassifier.html\">?<span>Documentation for AdaBoostClassifier</span></a></label><div class=\"sk-toggleable__content \"><pre>AdaBoostClassifier(algorithm=&#x27;SAMME&#x27;, learning_rate=0.9665397922726,\n",
       "                   n_estimators=320)</pre></div> </div></div></div></div></div></div></div></div>"
      ],
      "text/plain": [
       "Pipeline(steps=[('maskselector',\n",
       "                 MaskSelector(mask=array([False, False,  True, False, False, False, False, False, False,\n",
       "        True, False, False]))),\n",
       "                ('pipeline',\n",
       "                 Pipeline(steps=[('normalizer', Normalizer(norm='l1')),\n",
       "                                 ('selectpercentile',\n",
       "                                  SelectPercentile(percentile=74.2561844719571)),\n",
       "                                 ('featureunion-1',\n",
       "                                  FeatureUnion(transformer_list=[('featureunion',\n",
       "                                                                  FeatureUnion(transformer_list=[('binarizer',\n",
       "                                                                                                  Binarizer(threshold=0.0935770250992))])),\n",
       "                                                                 ('passthrough',\n",
       "                                                                  Passthrough())])),\n",
       "                                 ('featureunion-2',\n",
       "                                  FeatureUnion(transformer_list=[('skiptransformer',\n",
       "                                                                  SkipTransformer()),\n",
       "                                                                 ('passthrough',\n",
       "                                                                  Passthrough())])),\n",
       "                                 ('adaboostclassifier',\n",
       "                                  AdaBoostClassifier(algorithm='SAMME',\n",
       "                                                     learning_rate=0.9665397922726,\n",
       "                                                     n_estimators=320))]))])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear_search_space = tpot.config.template_search_spaces.get_template_search_spaces(\"linear\", classification=True)\n",
    "gfs_and_linear_search_space = SequentialPipeline([gfs_sp, linear_search_space])\n",
    "\n",
    "# est = tpot.TPOTEstimator(  \n",
    "#                            population_size=32,\n",
    "#                            generations=10, \n",
    "#                            scorers=[\"roc_auc_ovr\", tpot.objectives.complexity_scorer],\n",
    "#                            scorers_weights=[1.0, -1.0],\n",
    "#                            other_objective_functions=[number_of_selected_features],\n",
    "#                            other_objective_functions_weights = [-1],\n",
    "#                            objective_function_names = [\"Number of selected features\"],\n",
    "\n",
    "#                            n_jobs=32,\n",
    "#                            classification=True,\n",
    "#                            search_space = gfs_and_linear_search_space,\n",
    "#                            verbose=2,\n",
    "#                             )\n",
    "\n",
    "gfs_and_linear_search_space.generate(rng=1).export_pipeline()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Getting Fancy\n",
    "\n",
    "If you want to get fancy, you can combine more search spaces in order to set up unique preprocessing pipelines per feature set. Here's an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-3 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-3 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-3 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-3 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-3 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-3 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-3 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-3 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-3 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-3 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-3 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-3 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-3 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-3 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-3 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-3 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-3 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-3 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-3\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;featureunion&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;pipeline&#x27;,\n",
       "                                                 Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                                                                  MaskSelector(mask=array([False,  True, False, False, False, False, False, False,  True,\n",
       "       False, False, False]))),\n",
       "                                                                 (&#x27;pipeline&#x27;,\n",
       "                                                                  Pipeline(steps=[(&#x27;featureunion-1&#x27;,\n",
       "                                                                                   FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                                   FeatureUnion(transformer_list=[(&#x27;robustscaler&#x27;,\n",
       "                                                                                                                                                   Robu...\n",
       "                                                                                   FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                                   FeatureUnion(transformer_list=[(&#x27;normalizer&#x27;,\n",
       "                                                                                                                                                   Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                                                                                                                                  (&#x27;nystroem&#x27;,\n",
       "                                                                                                                                                   Nystroem(gamma=0.5186832611359,\n",
       "                                                                                                                                                            kernel=&#x27;polynomial&#x27;,\n",
       "                                                                                                                                                            n_components=3))])),\n",
       "                                                                                                                  (&#x27;passthrough&#x27;,\n",
       "                                                                                                                   Passthrough())]))]))]))])),\n",
       "                (&#x27;sgdclassifier&#x27;,\n",
       "                 SGDClassifier(alpha=0.0024802032445, eta0=0.2824117602653,\n",
       "                               l1_ratio=0.281711265998, loss=&#x27;modified_huber&#x27;,\n",
       "                               n_jobs=1, penalty=&#x27;elasticnet&#x27;))])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-16\" type=\"checkbox\" ><label for=\"sk-estimator-id-16\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;&nbsp;Pipeline<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link \">i<span>Not fitted</span></span></label><div class=\"sk-toggleable__content \"><pre>Pipeline(steps=[(&#x27;featureunion&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;pipeline&#x27;,\n",
       "                                                 Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                                                                  MaskSelector(mask=array([False,  True, False, False, False, False, False, False,  True,\n",
       "       False, False, False]))),\n",
       "                                                                 (&#x27;pipeline&#x27;,\n",
       "                                                                  Pipeline(steps=[(&#x27;featureunion-1&#x27;,\n",
       "                                                                                   FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                                   FeatureUnion(transformer_list=[(&#x27;robustscaler&#x27;,\n",
       "                                                                                                                                                   Robu...\n",
       "                                                                                   FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                                   FeatureUnion(transformer_list=[(&#x27;normalizer&#x27;,\n",
       "                                                                                                                                                   Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                                                                                                                                  (&#x27;nystroem&#x27;,\n",
       "                                                                                                                                                   Nystroem(gamma=0.5186832611359,\n",
       "                                                                                                                                                            kernel=&#x27;polynomial&#x27;,\n",
       "                                                                                                                                                            n_components=3))])),\n",
       "                                                                                                                  (&#x27;passthrough&#x27;,\n",
       "                                                                                                                   Passthrough())]))]))]))])),\n",
       "                (&#x27;sgdclassifier&#x27;,\n",
       "                 SGDClassifier(alpha=0.0024802032445, eta0=0.2824117602653,\n",
       "                               l1_ratio=0.281711265998, loss=&#x27;modified_huber&#x27;,\n",
       "                               n_jobs=1, penalty=&#x27;elasticnet&#x27;))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-17\" type=\"checkbox\" ><label for=\"sk-estimator-id-17\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;featureunion: FeatureUnion<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.FeatureUnion.html\">?<span>Documentation for featureunion: FeatureUnion</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureUnion(transformer_list=[(&#x27;pipeline&#x27;,\n",
       "                                Pipeline(steps=[(&#x27;maskselector&#x27;,\n",
       "                                                 MaskSelector(mask=array([False,  True, False, False, False, False, False, False,  True,\n",
       "       False, False, False]))),\n",
       "                                                (&#x27;pipeline&#x27;,\n",
       "                                                 Pipeline(steps=[(&#x27;featureunion-1&#x27;,\n",
       "                                                                  FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                  FeatureUnion(transformer_list=[(&#x27;robustscaler&#x27;,\n",
       "                                                                                                                                  RobustScaler(quantile_range=(0.18740...\n",
       "                                                                                                                                  FeatureAgglomeration(linkage=&#x27;complete&#x27;,\n",
       "                                                                                                                                                       metric=&#x27;l2&#x27;,\n",
       "                                                                                                                                                       n_clusters=28))])),\n",
       "                                                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                                                  Passthrough())])),\n",
       "                                                                 (&#x27;featureunion-2&#x27;,\n",
       "                                                                  FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                                                                  FeatureUnion(transformer_list=[(&#x27;normalizer&#x27;,\n",
       "                                                                                                                                  Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                                                                                                                 (&#x27;nystroem&#x27;,\n",
       "                                                                                                                                  Nystroem(gamma=0.5186832611359,\n",
       "                                                                                                                                           kernel=&#x27;polynomial&#x27;,\n",
       "                                                                                                                                           n_components=3))])),\n",
       "                                                                                                 (&#x27;passthrough&#x27;,\n",
       "                                                                                                  Passthrough())]))]))]))])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>pipeline</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-18\" type=\"checkbox\" ><label for=\"sk-estimator-id-18\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">MaskSelector</label><div class=\"sk-toggleable__content \"><pre>MaskSelector(mask=array([False,  True, False, False, False, False, False, False,  True,\n",
       "       False, False, False]))</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-19\" type=\"checkbox\" ><label for=\"sk-estimator-id-19\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;pipeline: Pipeline<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for pipeline: Pipeline</span></a></label><div class=\"sk-toggleable__content \"><pre>Pipeline(steps=[(&#x27;featureunion-1&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                 FeatureUnion(transformer_list=[(&#x27;robustscaler&#x27;,\n",
       "                                                                                 RobustScaler(quantile_range=(0.1874078711948,\n",
       "                                                                                                              0.7642865555088))),\n",
       "                                                                                (&#x27;featureagglomeration&#x27;,\n",
       "                                                                                 FeatureAgglomeration(linkage=&#x27;complete&#x27;,\n",
       "                                                                                                      metric=&#x27;l2&#x27;,\n",
       "                                                                                                      n_clusters=28))])),\n",
       "                                                (&#x27;passthrough&#x27;,\n",
       "                                                 Passthrough())])),\n",
       "                (&#x27;featureunion-2&#x27;,\n",
       "                 FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                                 FeatureUnion(transformer_list=[(&#x27;normalizer&#x27;,\n",
       "                                                                                 Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                                                                (&#x27;nystroem&#x27;,\n",
       "                                                                                 Nystroem(gamma=0.5186832611359,\n",
       "                                                                                          kernel=&#x27;polynomial&#x27;,\n",
       "                                                                                          n_components=3))])),\n",
       "                                                (&#x27;passthrough&#x27;,\n",
       "                                                 Passthrough())]))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-20\" type=\"checkbox\" ><label for=\"sk-estimator-id-20\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;featureunion-1: FeatureUnion<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.FeatureUnion.html\">?<span>Documentation for featureunion-1: FeatureUnion</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                FeatureUnion(transformer_list=[(&#x27;robustscaler&#x27;,\n",
       "                                                                RobustScaler(quantile_range=(0.1874078711948,\n",
       "                                                                                             0.7642865555088))),\n",
       "                                                               (&#x27;featureagglomeration&#x27;,\n",
       "                                                                FeatureAgglomeration(linkage=&#x27;complete&#x27;,\n",
       "                                                                                     metric=&#x27;l2&#x27;,\n",
       "                                                                                     n_clusters=28))])),\n",
       "                               (&#x27;passthrough&#x27;, Passthrough())])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>featureunion</label></div></div><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>robustscaler</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-21\" type=\"checkbox\" ><label for=\"sk-estimator-id-21\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;RobustScaler<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.RobustScaler.html\">?<span>Documentation for RobustScaler</span></a></label><div class=\"sk-toggleable__content \"><pre>RobustScaler(quantile_range=(0.1874078711948, 0.7642865555088))</pre></div> </div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>featureagglomeration</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-22\" type=\"checkbox\" ><label for=\"sk-estimator-id-22\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;FeatureAgglomeration<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.cluster.FeatureAgglomeration.html\">?<span>Documentation for FeatureAgglomeration</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureAgglomeration(linkage=&#x27;complete&#x27;, metric=&#x27;l2&#x27;, n_clusters=28)</pre></div> </div></div></div></div></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>passthrough</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-23\" type=\"checkbox\" ><label for=\"sk-estimator-id-23\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">Passthrough</label><div class=\"sk-toggleable__content \"><pre>Passthrough()</pre></div> </div></div></div></div></div></div></div><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-24\" type=\"checkbox\" ><label for=\"sk-estimator-id-24\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;featureunion-2: FeatureUnion<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.FeatureUnion.html\">?<span>Documentation for featureunion-2: FeatureUnion</span></a></label><div class=\"sk-toggleable__content \"><pre>FeatureUnion(transformer_list=[(&#x27;featureunion&#x27;,\n",
       "                                FeatureUnion(transformer_list=[(&#x27;normalizer&#x27;,\n",
       "                                                                Normalizer(norm=&#x27;l1&#x27;)),\n",
       "                                                               (&#x27;nystroem&#x27;,\n",
       "                                                                Nystroem(gamma=0.5186832611359,\n",
       "                                                                         kernel=&#x27;polynomial&#x27;,\n",
       "                                                                         n_components=3))])),\n",
       "                               (&#x27;passthrough&#x27;, Passthrough())])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>featureunion</label></div></div><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>normalizer</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-25\" type=\"checkbox\" ><label for=\"sk-estimator-id-25\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;Normalizer<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.Normalizer.html\">?<span>Documentation for Normalizer</span></a></label><div class=\"sk-toggleable__content \"><pre>Normalizer(norm=&#x27;l1&#x27;)</pre></div> </div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>nystroem</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-26\" type=\"checkbox\" ><label for=\"sk-estimator-id-26\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;Nystroem<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.kernel_approximation.Nystroem.html\">?<span>Documentation for Nystroem</span></a></label><div class=\"sk-toggleable__content \"><pre>Nystroem(gamma=0.5186832611359, kernel=&#x27;polynomial&#x27;, n_components=3)</pre></div> </div></div></div></div></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label  sk-toggleable\"><label>passthrough</label></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-27\" type=\"checkbox\" ><label for=\"sk-estimator-id-27\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">Passthrough</label><div class=\"sk-toggleable__content \"><pre>Passthrough()</pre></div> </div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator  sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-28\" type=\"checkbox\" ><label for=\"sk-estimator-id-28\" class=\"sk-toggleable__label  sk-toggleable__label-arrow \">&nbsp;SGDClassifier<a class=\"sk-estimator-doc-link \" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.linear_model.SGDClassifier.html\">?<span>Documentation for SGDClassifier</span></a></label><div class=\"sk-toggleable__content \"><pre>SGDClassifier(alpha=0.0024802032445, eta0=0.2824117602653,\n",
       "              l1_ratio=0.281711265998, loss=&#x27;modified_huber&#x27;, n_jobs=1,\n",
       "              penalty=&#x27;elasticnet&#x27;)</pre></div> </div></div></div></div></div></div>"
      ],
      "text/plain": [
       "Pipeline(steps=[('featureunion',\n",
       "                 FeatureUnion(transformer_list=[('pipeline',\n",
       "                                                 Pipeline(steps=[('maskselector',\n",
       "                                                                  MaskSelector(mask=array([False,  True, False, False, False, False, False, False,  True,\n",
       "       False, False, False]))),\n",
       "                                                                 ('pipeline',\n",
       "                                                                  Pipeline(steps=[('featureunion-1',\n",
       "                                                                                   FeatureUnion(transformer_list=[('featureunion',\n",
       "                                                                                                                   FeatureUnion(transformer_list=[('robustscaler',\n",
       "                                                                                                                                                   Robu...\n",
       "                                                                                   FeatureUnion(transformer_list=[('featureunion',\n",
       "                                                                                                                   FeatureUnion(transformer_list=[('normalizer',\n",
       "                                                                                                                                                   Normalizer(norm='l1')),\n",
       "                                                                                                                                                  ('nystroem',\n",
       "                                                                                                                                                   Nystroem(gamma=0.5186832611359,\n",
       "                                                                                                                                                            kernel='polynomial',\n",
       "                                                                                                                                                            n_components=3))])),\n",
       "                                                                                                                  ('passthrough',\n",
       "                                                                                                                   Passthrough())]))]))]))])),\n",
       "                ('sgdclassifier',\n",
       "                 SGDClassifier(alpha=0.0024802032445, eta0=0.2824117602653,\n",
       "                               l1_ratio=0.281711265998, loss='modified_huber',\n",
       "                               n_jobs=1, penalty='elasticnet'))])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dynamic_transformers = DynamicUnionPipeline(get_search_space(\"all_transformers\"), max_estimators=4)\n",
    "dynamic_transformers_with_passthrough = tpot.search_spaces.pipelines.UnionPipeline([\n",
    "    dynamic_transformers,\n",
    "    tpot.config.get_search_space(\"Passthrough\")],\n",
    "    )\n",
    "multi_step_engineering = DynamicLinearPipeline(dynamic_transformers_with_passthrough, max_length=4)\n",
    "gfs_engineering_search_space = SequentialPipeline([gfs_sp, multi_step_engineering])\n",
    "union_fss_engineering_search_space = DynamicUnionPipeline(gfs_engineering_search_space)\n",
    "classification_search_space = get_search_space('classifiers')\n",
    "\n",
    "final_fancy_search_space = SequentialPipeline([union_fss_engineering_search_space, classification_search_space])\n",
    "\n",
    "final_fancy_search_space.generate(rng=1).export_pipeline()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tpotenv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
